
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Spring AOP（面向切面编程） - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>Spring AOP（面向切面编程） - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">Spring AOP 中的五个核心概念分别是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">五个核心概念是：1. 切面（Aspect）：横切关注点的模块化。2. 连接点（JoinPoint）：程序执行过程中能够插入切面的点。3. 通知（Advice）：切面在连接点的执行行为。4. 切入点（Pointcut）：通知应用的具体位置。5. 代理（Proxy）：Spring AOP 通过代理对象来增强目标对象的功能。</div>
          </div>
          <div class="card-source">来源: 1. Spring AOP 的基础概念</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">Spring AOP 提供了哪两种类型的代理？它们分别适用于什么场景？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Spring AOP 提供两种代理类型：1. JDK 动态代理：适用于目标对象实现了接口的情况。2. CGLIB 代理：适用于目标类没有实现接口的情况。</div>
          </div>
          <div class="card-source">来源: 2. AOP 的实现方式：代理模式</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在使用 CGLIB 代理时，哪个核心类被用来创建代理子类？它通过设置什么来拦截方法调用？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`Enhancer`是CGLIB的核心类，它通过创建目标对象的代理子类，并设置回调方法（如`AopInterceptor`）来拦截方法调用。</div>
          </div>
          <div class="card-source">来源: 2.2. CGLIB 代理的实现</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">核心类</div>
          <div class="card-question">在 Spring AOP 中，`AdvisedSupport` 类的作用是什么？它包含了哪些关键信息？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">核心类</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`AdvisedSupport` 是 Spring AOP 配置和支持的核心类，是 AOP 代理的基础。它包含了目标对象（target）、增强器集合（advisors）和目标来源（targetSource）等信息。</div>
          </div>
          <div class="card-source">来源: 3.1. AdvisedSupport</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">核心类</div>
          <div class="card-question">请描述 `TargetSource` 接口在 Spring AOP 中的作用及其提供的关键方法。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">核心类</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`TargetSource` 是一个用来获取目标对象的重要接口。它提供了三个关键方法：`getTarget()` 用于获取目标对象，`getTargetClass()` 用于返回目标对象的类信息，以及 `isStatic()` 用于判断目标对象是否是单例的。</div>
          </div>
          <div class="card-source">来源: 3.2. TargetSource</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">Spring AOP 支持哪五种类型的通知（Advice）？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Spring AOP 支持五种通知类型：前置通知（Before）、后置通知（After）、返回通知（AfterReturning）、异常通知（AfterThrowing）和环绕通知（Around）。</div>
          </div>
          <div class="card-source">来源: 5. 通知（Advice）的类型与实现</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">如何使用 AspectJ 注解定义一个切面，并声明一个前置通知？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">通过在类上使用 `@Aspect` 注解来定义一个切面。在切面类的方法上使用 `@Before` 注解来声明一个前置通知，并通过一个切入点表达式（例如 `execution(* com.example.service.*.*(..))`）来指定其应用的位置。</div>
          </div>
          <div class="card-source">来源: 4.1. AspectJ 切面与注解方式</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">环绕通知（@Around）的特殊性体现在哪里？在环绕通知内部如何调用原始的目标方法？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">环绕通知（@Around）的特殊性在于它可以在目标方法调用前后都执行自定义代码。在通知内部，通过调用 `ProceedingJoinPoint` 对象的 `proceed()` 方法来执行目标方法。</div>
          </div>
          <div class="card-source">来源: 4.2. AspectJ Expression</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">Spring AOP 是如何决定为目标对象创建 JDK 动态代理还是 CGLIB 代理的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Spring 通过 `AopProxyFactory` 来选择合适的代理类型。根据文档中的源码示例，它会判断配置中 `TargetSource` 的 `isStatic()` 方法返回值，如果为 true，则创建 JDK 动态代理；否则，创建 CGLIB 代理。</div>
          </div>
          <div class="card-source">来源: 6.1. AOP 代理的创建</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
